package normal_server

import (
	"fmt"
	"github.com/google/uuid"
	"github.com/patrickmn/go-cache"
	"io"
	"log"
	"net/http"
	"net/url"
	"ssoAndAuth2/sso"
	"time"
)

var (
	ssoServer       = "http://sso.com:8082"
	codeValidateApi = "/code/validate"
)

type Handler func(http.ResponseWriter, *http.Request)

type Middleware func(Handler) Handler

type Server struct {
	tokenName     string
	tokenDuration time.Duration
	session       *cache.Cache
	clientId      string
}

type ServerConfig struct {
	tokenName     string
	tokenDuration time.Duration
	clientId      string
}

func NewServer(config *ServerConfig) *Server {
	return &Server{tokenName: config.tokenName, session: cache.New(config.tokenDuration, time.Second*30), clientId: config.clientId, tokenDuration: config.tokenDuration}
}

func (s *Server) hasCookie(r *http.Request) bool {
	cookie, err := r.Cookie(s.tokenName)
	if err != nil {
		return false
	}
	if cookie.Value == "" {
		return false
	}
	_, ok := s.session.Get(cookie.Value)
	if !ok {
		return false
	}
	return true
}

func (s *Server) hasCode(w http.ResponseWriter, r *http.Request) bool {
	code := r.URL.Query().Get("code")
	if code == "" {
		return false
	}
	data := url.Values{}
	data.Set("code", code)
	data.Set("signature", sso.MyEncrypt.Encrypt(s.clientId))

	resp, err := http.PostForm(ssoServer+codeValidateApi, data)
	if err != nil {
		log.Println(err.Error())
		return false
	}
	defer resp.Body.Close()
	var bs []byte
	bs, err = io.ReadAll(resp.Body)
	if err != nil {
		log.Println(err.Error())
		return false
	}
	if len(bs) != 0 {
		// 存在报错信息
		log.Println(string(bs))
		return false
	}

	// code验证合法，设置sever_a的token
	token := uuid.New()
	http.SetCookie(w, &http.Cookie{
		Name:    s.tokenName,
		Value:   token.String(),
		Expires: time.Now().Add(s.tokenDuration),
		Path:    "/",
	})
	s.session.Set(token.String(), "", s.tokenDuration)
	return true
}

func (s *Server) isLogin(w http.ResponseWriter, r *http.Request) bool {
	ok := s.hasCookie(r)
	if ok {
		return true
	}
	return s.hasCode(w, r)
}

func (s *Server) LoginMiddleware(next Handler) Handler {
	return func(w http.ResponseWriter, r *http.Request) {
		ok := s.isLogin(w, r)
		if !ok {
			// 未登录
			redirect := r.URL.Path
			http.Redirect(w, r, fmt.Sprintf("%s/login?clientId=%s&redirect=%s", ssoServer, s.clientId, redirect), http.StatusFound)
			return
		}
		next(w, r)
	}
}
